#include "GLBitmapFont.h"
namespace mp_gl
{
	using namespace std;

	GLBitmapFont::GLBitmapFont()
	{
		//Set cursor to beginning
		m_cur[X] = 0;
		m_cur[Y] = 0;
		//Set color to white
		m_clr[R] = 1.0f;
		m_clr[G] = 1.0f;
		m_clr[B] = 1.0f;
		m_clr[A] = 1.0f;
		//
		m_invertYAxis = false;
	}

	GLBitmapFont::~GLBitmapFont(){
		//Possible error
		Unbind();
	}

	bool GLBitmapFont::Load(char *fname)
	{
		char* data;
		char* img;
		fstream in;
		unsigned long fileSize;
		char bpp;
		int imgCoord[2];

		//Open the file
		in.open(fname, ios_base::binary | ios_base::in);
		//Return false on failure to open
		if(in.fail())
			return false;

		//Get the file size
		in.seekg(0, ios_base::end); //Cur to end
		fileSize = in.tellg();		//Cur location
		in.seekg(0,ios_base::beg);	//Cur back to beginning

		//Allocate the space needed
		data = new char[fileSize];
		//Check for allocation
		if(!data)
			return false;

		//Read in the data
		in.read(data,fileSize);
		//If failed to read data
		if(in.fail())
		{
			//Delete allocated data
			delete [] data;
			//Close read stream
			in.close();
			//Return false
			return false;
		}

		//Close read stream
		in.close();

		// Check ID is 'BFF2'
		if((unsigned char)data[0]!=0xBF || (unsigned char)data[1]!=0xF2)
		{
			delete [] data;
			return false;
		}

		//Grab header information
		memcpy(&imgCoord[X],&data[2],sizeof(int));
		memcpy(&imgCoord[Y],&data[6],sizeof(int));
		memcpy(&m_cell[X],&data[10],sizeof(int));
		memcpy(&m_cell[Y],&data[14],sizeof(int));
		bpp=data[18];
		m_base=data[19];

		// Check file size
		if(  fileSize!=((MAP_DATA_OFFSET)+ ((imgCoord[X]*imgCoord[Y])*(bpp/8) ))  )
		{
			return false;
		}


		// Calculate font params
		m_rowPitch	= imgCoord[X]/m_cell[X];
		m_colFactor	= (float)m_cell[X]/(float)imgCoord[X];
		m_rowFactor	= (float)m_cell[Y]/(float)imgCoord[Y];
		m_yOffset	= m_cell[Y];

		// Determine blending options based on BPP
		switch(bpp)
		{
		case 8: // Greyscale
			m_renderStyle = BFG_RS_ALPHA;
			break;

		case 24: // RGB
			m_renderStyle = BFG_RS_RGB;
			break;

		case 32: // RGBA
			m_renderStyle = BFG_RS_RGBA;
			break;

		default: // Unsupported BPP
			delete [] data;
			return false;
			break;
		}

		// Allocate space for image
		img=new char[(imgCoord[X]*imgCoord[Y])*(bpp/8)];
		// IF image space failed to allocate
		if(!img)
		{
			delete [] data;
			return false;
		}

		// Grab char widths
		memcpy(m_width,&data[WIDTH_DATA_OFFSET],256);

		// Grab image data
		memcpy(img,&data[MAP_DATA_OFFSET],(imgCoord[X]*imgCoord[Y])*(bpp/8));

		// Create Texture
		glGenTextures(1,&m_texID);
		glBindTexture(GL_TEXTURE_2D,m_texID);
		// Fonts should be rendered at native resolution so no need for texture filtering
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
		// Stop characters from bleeding over edges
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);

		// Tex creation parameters are dependent on BPP
		switch(m_renderStyle)
		{
		case BFG_RS_ALPHA:
			glTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE,imgCoord[X],imgCoord[Y],0,GL_LUMINANCE,GL_UNSIGNED_BYTE,img);
			break;

		case BFG_RS_RGB:
			glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,imgCoord[X],imgCoord[Y],0,GL_RGB,GL_UNSIGNED_BYTE,img);
			break;

		case BFG_RS_RGBA:
			glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,imgCoord[X],imgCoord[Y],0,GL_RGBA,GL_UNSIGNED_BYTE,img);
			break;
		}

		// Clean up
		delete [] img;
		delete [] data;

		return true;
	}

	void GLBitmapFont::SetScreen(int x, int y)
	{
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		if(m_invertYAxis)
			glOrtho(0,x,y,0,-1,1);
		else
			glOrtho(0,x,0,y,-1,1);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
	}

	void GLBitmapFont::SetCursor(int x, int y)
	{
		m_cur[X] = x;
		m_cur[Y] = y;
	}

	void GLBitmapFont::SetColor(float Red, float Green, float Blue, float Alpha)
	{
		m_clr[R] = Red;
		m_clr[G] = Green;
		m_clr[B] = Blue;
		m_clr[A] = Alpha;
	}

	void GLBitmapFont::ReverseYAxis(bool State)
	{
		if (State)
			m_yOffset =- m_cell[Y];
		else
			m_yOffset = m_cell[Y];
		m_invertYAxis = State;
	}

	void GLBitmapFont::Select()
	{
		glEnable(GL_TEXTURE_2D);
		Bind();
		SetBlend();
	}
     
	void GLBitmapFont::Bind()
	{
		glBindTexture(GL_TEXTURE_2D,m_texID);
	}

	void GLBitmapFont::Unbind()
	{
		glBindTexture(GL_TEXTURE_2D,m_texID);
	}
       
	void GLBitmapFont::SetBlend()
	{
		//Set color
		glColor4f(m_clr[R], m_clr[G], m_clr[B], m_clr[A]);
		switch(m_renderStyle)
		{
		case BFG_RS_ALPHA: // 8Bit
			glBlendFunc(GL_SRC_ALPHA,GL_SRC_ALPHA);
			glEnable(GL_BLEND);
			break;
		case BFG_RS_RGB:   // 24Bit
			glDisable(GL_BLEND);
			break;
		case BFG_RS_RGBA:  // 32Bit
			glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
			glEnable(GL_BLEND);
			break;
		}
	}
 
	void GLBitmapFont::Print(const char *Text)
	{
		
	}
     
	void GLBitmapFont::Print(const char *Text, int x, int y)
	{
		int sLen;
		int col;
		int row;
		float U;
		float V;
		float U1;
		float V1;

		m_cur[X] = x;
		m_cur[Y] = y;

		sLen=(int)strnlen(Text,BFG_MAXSTRING);

		glBegin(GL_QUADS);

		for(int i = 0; i != sLen; i++)
		{
			row = (Text[i]-m_base)/m_rowPitch;
			col = (Text[i]-m_base)-row*m_rowPitch;

			U  = col*m_colFactor;
			V  = row*m_rowFactor;
			U1 = U+m_colFactor;
			V1 = V+m_rowFactor;

			glTexCoord2f(U, V1); glVertex2i(m_cur[X],			m_cur[Y]);
			glTexCoord2f(U1,V1); glVertex2i(m_cur[X]+m_cell[X], m_cur[Y]);
			glTexCoord2f(U1,V ); glVertex2i(m_cur[X]+m_cell[X], m_cur[Y]+m_yOffset);
			glTexCoord2f(U, V ); glVertex2i(m_cur[X],			m_cur[Y]+m_yOffset);

			m_cur[X] += m_width[Text[i]];
		}
		glEnd();

	}

	int  GLBitmapFont::GetWidth(char *Text)
	{
		int sLength;
		int size = 0;
		sLength = (int)strnlen(Text,BFG_MAXSTRING);
		for(int i = 0; i != sLength; i++)
		{
			size += m_width[Text[i]];
		}
		return size;
	}


}